/*********************************************************************************************//**
* \file cartesd.h
* \author Daneluzzi F., Pelloux-Prayer J., Battandier P.
* \version 1
* \date janvier 2012
* \brief Bibliothèque contenant les fonctions utilisées pour la gestion de la carte SD.
* \defgroup sd_group Module SD
* @{
*************************************************************************************************/
#ifndef _carte_sd_h_
#define _carte_sd_h_

#include <portb.h>
#include <spi.h>
#include <delays.h>

#include "config.h"

/*! \def POINTER_ADDR
 *  \brief Adresse du secteur des pointeurs permettant de savoir l'occupation de la carte SD
 */
#define POINTER_ADDR            0
/*! \def POINTER_SIZE
 *  \brief Taille des pointeurs : 3 octets pour le secteur, 2 pour les 256 premiers octets d'un blocs et 2 pour les 256 derniers
 */
#define POINTER_SIZE            7
/*! \def POINTER_SIZE
 *  \brief Taille des blocs
 */
#define BLOCK_SIZE            512

/*! \enum SD_RESP
 *  \brief Les différents types de réponse
 */
typedef enum
{
    R1,     /*!< Standard response (48bits) */
    R1b,    /*!< Same as R1 with additional busy signal transmitted on the data line */
    R2,     /*!< The content of the CID register is sent as a response to CMD2 and CMD10 (136 bits) */
    R3      /*!< Only for READ_OCR command */
} SD_RESP;

/*! \struct SD_sCMD
 *  \brief Structure des commandes
 */
typedef struct
{
    unsigned char   cmdCode;            /*!< Command number */
    unsigned char   CRC;                /*!< CRC */
    SD_RESP         responseType;       /*!< Response type */
    unsigned char   moreDataExpected;   /*!< True if more data expected */
} SD_sCMD;

#define SD_BAD_RESPONSE     0xFF
#define SD_OK_RESPONSE      0x00

#define SD_ILLEGAL_CMD      0x04
#define SD_GOOD_CMD         0x00

#define SD_DATA_START_TOKEN 0xFE
#define DATA_ACCEPTED       0x05

#define MOREDATA            !0
#define NODATA              0

/*! \enum SD_STATUS
 *  \brief Définit les statuts de la carte SD
 */
typedef enum
{
    SD_STATUS_VALID = 0,            /*!< Everything is golden */
    SD_STATUS_INIT_COM_FAILURE,     /*!< Communication has never been established with card */
    SD_STATUS_NOT_INIT_FAILURE,     /*!< Card did not go into an initialization phase */
    SD_STATUS_INIT_TIMEOUT,         /*!< Card initialization has timeout */
    SD_STATUS_TYPE_INVALID,         /*!< Card type was not able to be defined */
    SD_STATUS_BAD_CMD,              /*!< Card did not recognized the command */
    SD_STATUS_TIMEOUT,              /*!< Card timeout during a read, write or erase sequence */
    SD_STATUS_CRC_ERROR,            /*!< A CRC error has occurred during a read, data should be invalidated */
    SD_STATUS_DATA_REJECTED,        /*!< Card and data sent's CRC did not match */
    SD_STATUS_ERASE_TIMEDOUT        /*!< Erase took longer than it should have */
} SD_STATUS;


/*! \enum SD_STATUS
 *  \brief Les commandes SPI pour la carte SD implémentées
 */
typedef enum
{
    GO_IDLE_STATE,      /*!< Software reset command */
    SEND_OP_COND,       /*!< Software reset command */
    SEND_CSD,           /*!< Software reset command */
    SEND_CID,           /*!< Software reset command */
    SET_BLOCKLEN,       /*!< Software reset command */
    READ_SINGLE_BLOCK,  /*!< Software reset command */
    WRITE_SINGLE_BLOCK  /*!< Software reset command */
} SD_CMD;


/*! \addtogroup commande_SPI
* \brief Valeurs des commandes SPI pour la carte SD
* @{
*/
/*! \def SD_CMD_GO_IDLE_STATE 
 *  \brief Go to idle state command
 *
 * Resets the SD Memory Car 
 */
#define SD_CMD_GO_IDLE_STATE     0x40
/*! \def SD_CMD_SEND_OP_COND        
 *  \brief Operational conditions command
 *
 * Sends host capacity support information and activates the card's initialization process. HCS is effective when card receives SEND_IF_COND command. Reserved bits shall be set to '0'. 
 */
#define SD_CMD_SEND_OP_COND      0x41
/*! \def SD_CMD_SEND_CSD            
 *  \brief Send csd command
 *
 * Asks the selected card to send its card-specific data (CSD) 
 */
#define SD_CMD_SEND_CSD          0x49
/*! \def SD_CMD_SEND_CID            
 *  \brief Send cid command
 *
 * Asks the selected card to send its card identification (CID) 
 */
#define SD_CMD_SEND_CID          0x4A
/*! \def SD_CMD_SET_BLOCKLEN        
 *  \brief Set block length command
 *
 * In case of SDSC Card, block length is set by this command. 
 */
#define SD_CMD_SET_BLOCKLEN      0x50
/*! \def SD_CMD_READ_SINGLE_BLOCK   
 *  \brief Read a single block command
 *
 * Reads a block of the size selected by the SET_BLOCKLEN command. 
 */
#define SD_CMD_READ_SINGLE_BLOCK 0x51
/*! \def SD_WRITE_SINGLE_BLOCK      
 *  \brief Write a single block command
 *
 * Writes a block of the size selected by the SET_BLOCKLEN command. 
 */
#define SD_WRITE_SINGLE_BLOCK    0x58
/*! @} */

/*!
 * \union SD_RESPONSE_R1
 * \brief Définit la structure d'une réponse du format R1
 */
typedef union
{
    unsigned char value;            /*!< R1 value */
    struct
    {
        unsigned IN_IDLE_STATE:1;   /*!< In idle state */
        unsigned ERASE_RESET:1;     /*!< An erase sequence was cleared before executing because an out of erase sequence command was received */
        unsigned ILLEGAL_CMD:1;     /*!< Command not legal for the card state */
        unsigned CRC_ERR:1;         /*!< The CRC check of the previous command failed. */
        unsigned ERASE_SEQ_ERR:1;   /*!< An error in the sequence of erase commands occurred. */
        unsigned ADDRESS_ERR:1;     /*!< A misaligned address which did not match the block length was used in the command. */
        unsigned PARAM_ERR:1;       /*!< An invalid selection of write-blocks for erase occurred.*/
        unsigned B7:1;              /*!< B7 */
    };
} SD_RESPONSE_R1;

/*!
 * \union SD_RESPONSE_R2
 * \brief Définit la structure d'une réponse du format R2
 */
typedef union
{
    unsigned int value;                     /*!< R2 value */
    struct
    {
        unsigned CARD_IS_LOCKED         :1; /*!< When set, signals that the card is locked by the host */
        unsigned WP_ERASE_SKIP_LK_FAIL  :1; /*!< Set when only partial address space was erased due to existing write protected blocks or the temporary or permanent write protected card was erased. */
        unsigned ERROR                  :1; /*!< A general or an unknown error occurred during the operation. */
        unsigned CC_ERROR               :1; /*!< Internal card controller error */
        unsigned CARD_ECC_FAIL          :1; /*!< Card internal ECC was applied but failed to correct the data. */
        unsigned WP_VIOLATION           :1; /*!< Set when the host attempts to write to a protected block or to the temporary or permanent write protected card. */
        unsigned ERASE_PARAM            :1; /*!< An invalid selection of write-blocks for erase occurred. */
        unsigned OUTRANGE_CSD_OVERWRITE :1; /*!< The command's argument was out of the allowed range for this card (CSD overwrite). */
    };
} SD_RESPONSE_R2;

/*!
 * \union SD_RESPONSE
 * \brief Définit les types de réponse possible de la carte SD
 */
typedef union
{
    SD_RESPONSE_R1  r1;     /*!< Type 1 of response */
    SD_RESPONSE_R2  r2;     /*!< Type 2 of response */
} SD_RESPONSE;

/*!
 * \union SD_CMD_PACKET
 * \brief Définit la structure d'une trame de commande SPI pour carte SD
 */
typedef union
{
    struct
    {
        unsigned char crc;      /*!< Packet CRC */
        unsigned char arg0;     /*!< Argument 0 of command */
        unsigned char arg1;     /*!< Argument 1 of command */
        unsigned char arg2;     /*!< Argument 2 of command */
        unsigned char arg3;     /*!< Argument 3 of command */
        unsigned char cmd;      /*!< Command of packet */
    };
    struct
    {
        unsigned CRC7:7;        /*!< Packet CRC */
        long arg;               /*!< Packet argument */
        unsigned char command;  /*!< Packet command */
    };
} SD_CMD_PACKET;

/****//**
* \union SD_CSD
* \brief Représente le registre CSD de la carte SD comme un tableau de char ou comme une structure
**/
typedef union
{
    char registre[16];                      /*!< char table of CSD */
    struct
    {
        unsigned CSD_STRUCTURE      :2;     /*!< Version of CSD */
        unsigned RESERVED_3         :6;     /*!< Reserved */
        unsigned TAAC               :8;     /*!< Data read access-time-1 */
        unsigned NSAC               :8;     /*!< Data read access-time-2 in CLK cycles (NSAC*100) */
        unsigned TRAN_SPEED         :8;     /*!< Maximum data transfer rate */
        unsigned CCC_H              :4;     /*!< Card command classes High */
        unsigned CCC_L              :8;     /*!< Card command classes Low */
        unsigned READ_BL_LEN        :4;     /*!< Maximum read data block length */
        unsigned READ_BL_PARTIAL    :1;     /*!< Partial blocks for read allowed */
        unsigned WRITE_BLK_MISALIGN :1;     /*!< Write block misalignment */
        unsigned READ_BLK_MISALIGN  :1;     /*!< Read block misalignment */
        unsigned DSR_IMP            :1;     /*!< DSR implemented */
        unsigned RESERVED_2         :2;     /*!< Reserved */
        unsigned C_SIZE_H           :4;     /*!< Device size high */
        unsigned C_SIZE_L           :8;     /*!< Device size low */
        unsigned VDD_R_CURR_MIN     :3;     /*!< Maximum read current at VDD min */
        unsigned VDD_R_CURR_MAX     :3;     /*!< Maximum read current at VDD max */
        unsigned VDD_W_CUR_MIN      :3;     /*!< Maximum write current at VDD min */
        unsigned VDD_W_CURR_MAX     :3;     /*!< Maximum write current at VDD max */
        unsigned C_SIZE_MULT        :3;     /*!< Device size multiplier */
        unsigned ERASE_BLK_EN       :1;     /*!< Erase single block enable */
        unsigned SECTOR_SIZE        :7;     /*!< Erase sector size */
        unsigned WP_GRP_SIZE        :7;     /*!< Write protect group size */
        unsigned WP_GRP_ENABLE      :1;     /*!< Write protect group enable */
        unsigned RESERVED_1         :2;     /*!< Reserved (Do not use) */
        unsigned R2W_FACTOR         :3;     /*!< Write speed factor */
        unsigned WRITE_BL_LEN       :4;     /*!< Maximum write data block length */
        unsigned WRITE_BL_PARTIAL   :1;     /*!< Partial blocks for write allowed */
        unsigned RESERVED_4         :5;     /*!< Reserved */
        unsigned FILE_FORMAT_GRP    :1;     /*!< File format group */
        unsigned COPY               :1;     /*!< Copy flag */
        unsigned PERM_WRITE_PROTECT :1;     /*!< Permanent write protection */
        unsigned TMP_WRITE_PROTECT  :1;     /*!< Temporary write protection */
        unsigned FILE_FORMAT        :2;     /*!< File format */
        unsigned ECC                :2;     /*!< Reserved */
        unsigned CRC                :7;     /*!< CRC */
        unsigned NOT_USED           :1;     /*!< Not used, always '1' */
    };
} SD_CSD;

/****//**
* \struct SD_CID
* \brief Représente le registre CID de la carte SD
**/
typedef struct
{
    unsigned char   MID;        /*!< Manufacture ID */
    unsigned int    OID;        /*!< OEM/Application ID */
    unsigned char   PNM[5];     /*!< Product Name */
    unsigned char   PRV;        /*!< Product Revision */
    unsigned long   PSN;        /*!< Serial Number (PSN) */
    unsigned        RSV:4;      /*!< Reserved */
    unsigned char   MDT;        /*!< Manufacturing Date Code (BCD) */
    unsigned        MDT2:4;     /*!< Manufacturing Date Code (BCD) */
    unsigned        CRC:7;      /*!< register CRC */
    unsigned        NOT_USED:1; /*!< Not used : always '1' */
} SD_CID;

/****//**
* \fn sd_init
* \brief
* Initialisation de l'hôte et de la carte SD.
**/
SD_STATUS sd_init(void);

/****//**
* \fn sd_init_host
* \brief
* Initialisation côté hôte.
**/
void sd_init_host(void);

/****//**
* \fn sd_init_card
* \brief
* Initialisation de la carte SD.
* \return Status de la carte SD.
**/
SD_STATUS sd_init_card(void);

/****//**
* \fn sd_read
* \brief
* Lecture de la carte SD
* \return Valeur lue
**/
unsigned char sd_read(void);

/****//**
* \fn sd_write
* \brief
* Écriture d'une commande et de ses arguments (éventuellement)
* \param [in] cmd : Commande à envoyer à la carte SD
* \param [in] arg : Arguments de la commande
* \return Réponse de la carte sd
**/
SD_RESPONSE sd_write(unsigned char cmd, long arg);

/****//**
* \fn sd_sector_read512
* \brief
* Lecture d'un secteur de la carte sd
* \param [in] sector_addr : adresse du bloc à lire
* \param [out] bufferHigh : contenu de poids fort du bloc
* \param [out] bufferLow  : contenu de poids faible du bloc
* \return Status de la carte sd
**/
SD_STATUS sd_sector_read512(long sector_addr, char *bufferHigh, char *bufferLow);

/****//**
* \fn sd_sector_write512
* \brief
* Écriture d'un bloc de 512o sur la carte sd
* \param [in] sector_addr : adresse du bloc a écrire
* \param [in] bufferHigh  : données de poids fort écrire
* \param [in] bufferLow   : données de poids faible écrire
* \return Status de la carte sd
**/
SD_STATUS sd_sector_write512(long sector_addr, char *bufferHigh, char *bufferLow);

/****//**
* \fn sd_detect
* \brief
* Détection de la carte SD
* \return Présence ou absence de la carte SD
**/
unsigned char sd_detect(void);

/****//**
* \fn sd_get_csd
* \brief
* Récupération du registre CSD de la carte SD
* \param [out] buffer : contenu du registre CSD
* \return Status de la carte sd
**/
SD_STATUS sd_get_csd(char *buffer);

/****//**
* \fn sd_get_cid
* \brief
* Récupération du registre CiD de la carte SD
* \param [out] buffer : contenu du registre CiD
* \return Status de la carte sd
**/
SD_STATUS sd_get_cid(char *buffer);

/****//**
* \fn add_measure
* \brief
* Écriture sur la carte SD de nouvelles données
* \param [in] buffer      : donnees écrire
* \param [in] bufferSize  : taille des données
* \return Status de la carte sd
**/
SD_STATUS add_measure(char *buffer, unsigned int bufferSize);

/****//**
* \fn read_pointer
* \brief
* Lecture sur la carte SD du pointeur
* \param [out] sectorPointer   : Valeur pointeur qui indique le bloc à écrire
* \param [out] bytePointerHigh : Valeur pointeur qui indique le byte à écrire parmi les 256 premiers octets.
* \param [out] bytePointerLow  : Valeur pointeur qui indique le byte à écrire parmi les 256 derniers octets.
* \return Status de la carte sd
**/
SD_STATUS read_pointer(long *sectorPointer, int *bytePointerHigh, int *bytePointerLow);

/****//**
* \fn write_pointer
* \brief
* Écriture sur la carte SD des pointeurs
* \param [in] sectorPointer   : Valeur pointeur qui indique le bloc à écrire.
* \param [in] bytePointerHigh : Valeur pointeur qui indique le byte à écrire parmi les 256 premiers octets.
* \param [in] bytePointerLow  : Valeur pointeur qui indique le byte à écrire parmi les 256 derniers octets.
* \return Status de la carte sd
**/
SD_STATUS write_pointer(long sectorPointer, int bytePointerHigh, int bytePointerLow);

/****//**
* \fn erase_pointer
* \brief
* Effacement de la carte mémoire.
* \return Status de la carte SD.
**/
SD_STATUS erase_pointer();

/****//**
* \fn read_state
* \brief
* Lit l'état d'occupation de la carte SD.
* \return Status de la carte SD.
**/
SD_STATUS read_state(long *status);

/****//**
* \fn sizeOfCard
* \brief
* Calcule la taille de la carte SD grâce au registre CSD
* \return Taille de la carte SD
**/
long sizeOfCard();

/** @}*/
#endif
